--library pakorobiol;
library ieee;
use ieee.NUMERIC_STD.all;
use ieee.std_logic_1164.all;
use work.all;
use constants.all;

	-- Add your library and packages declaration here ...

entity cpu_tb is
end cpu_tb;

architecture cpu_arch1_testbench of cpu_tb is
	-- Stimulus signals - signals mapped to the input and inout ports of tested entity
	signal clock : std_logic := '0';
	signal resetN : std_logic;
	signal imemData : b32;
	signal dmemDataRead : b32;	
	
	-- Observed signals - signals mapped to the output ports of tested entity
	signal imemAddr : b32;
	signal dmemAddrRead : b32;
	signal dmemAddrWrite : b32;
	signal dmemWrEna, dmemRdEna : std_logic;
	signal dmemDataWrite : b32;
	
	signal doWait : std_logic;
	
	constant cycleTime : time := 10 ns;
	constant resetTime : time := (cycleTime * 2);	
	
begin	
	
	-- Unit Under Test port map
	UUT : entity work.cpu
		port map (
			clock => clock,
			resetN => resetN,
			imemAddr => imemAddr,
			imemData => imemData,
			dmemAddrRead => dmemAddrRead,
			dmemAddrWrite => dmemAddrWrite,
			dmemWrEna => dmemWrEna,
			dmemRdEna => dmemRdEna,
			dmemDataRead => dmemDataRead,
			dmemDataWrite => dmemDataWrite,
			doWait => doWait
		);
		
	clock <= not clock after cycleTime / 2; 
	resetN <= '0', '1' after resetTime; 
	doWait <= '0';	
	
	testP: process	 		
		-------------------------------------
		-- theese are some simple unit tests
		-------------------------------------
		procedure cpuTest1 is
			variable addr : integer;
		begin
					-- mov 2, r0
			addr := to_integer(unsigned(imemAddr));
			assert addr = 0 severity error;
			imemData <= COND_ALWAYS & CLASS_ALU & UNUSED4 & ('1' & ALU_PASS_B) & '1'  & "-----" & "00010" & r0;		
			wait for cycleTime;
			
			-- mov 3, r1 
			addr := to_integer(unsigned(imemAddr));
			assert addr = 1;		
			imemData <= COND_ALWAYS & CLASS_ALU & UNUSED4 & ('1' & ALU_PASS_B) & '1'  & "-----" & "00011" & r1;
			wait for cycleTime;
			
			-- add r0, r1, r2
			addr := to_integer(unsigned(imemAddr));
			assert addr = 2;		
			imemData <= COND_ALWAYS & CLASS_ALU & UNUSED4 & ('1' & ALU_ADD) & '0'  & r0 & r1 & r2;
			wait for cycleTime;
			
			-- store r1 at r0
			addr := to_integer(unsigned(imemAddr));
			assert addr = 3;		
			imemData <= COND_ALWAYS & CLASS_LDST & UNUSED4 & F_LDST_STORE & '0'  & r0 & r1 & "-----";
			wait for cycleTime;
			
			addr := to_integer(unsigned(imemAddr));		
			assert addr = 4;
			assert dmemWrEna = '1' and dmemRdEna = '0';
			assert to_integer(unsigned(dmemAddrWrite)) = 2;
			assert to_integer(unsigned(dmemDataWrite)) = 3;
			
			-- test load
			imemData <= COND_ALWAYS & CLASS_LDST & UNUSED4 & F_LDST_LOAD & '0'  & r2 & "-----" & r3;
			wait for cycleTime;
			
			addr := to_integer(unsigned(imemAddr));		
			assert addr = 5;
			assert dmemRdEna = '1' and dmemWrEna = '0';
			assert to_integer(unsigned(dmemAddrRead)) = 5;
	
			
			imemData <= COND_ALWAYS & CLASS_JUMP & UNUSED4 & F_JUMP_ABS & '0'  & "-----" & r2 & "-----";
			wait for cycleTime;
			
			addr := to_integer(unsigned(imemAddr));		
			assert addr = 5;
			wait for cycleTime;
		end	procedure cpuTest1;
	begin
		wait for resetTime;
		cpuTest1;
		--cpuDebug
		wait;						
	end process testP;
	

--wait for 10 ns;   
-- timeout clause, specific time delay.
 	--wait until clk='1';          -- condition clause, Boolean condition
 	--wait until A>B and S1 or S2; -- condition clause, Boolean condition
 	--wait on sig1, sig2;          -- sensitivity clause, any event on any
	                              -- signal terminates wait
		
		--assert a=(b or c);
 		--assert j<i report "internal error, tell someone";
 		--assert clk='1' report "clock not up" severity WARNING;
		--report "test done";
		-- predefined severity names are: NOTE, WARNING, ERROR, FAILURE
 		--default severity for assert is ERROR		
		


end cpu_arch1_testbench;



